﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Globalization;
using System.IO;

namespace HDI.Charts2
{
    public class Coord : Chart
    {
        public enum ChartTypes { column, step, smoothedLine, line, }

        public Coord(string Name)
            : base(Name)
        {

        }
        public bool useDateTable { get; set; }

        public string cellFormating { get; set; }


        public override void init()
        {
            _Legend = new Legend(this);
            _vAxis = new ValueAxis(this);
            _cAxis = new CategoryAxis(this);
            _cCursor = new ChartCursor(this);
            setOption("categoryField", " 'cat'");
            setOption("startDuration", " 1");
            setOption("marginBottom", " 10");
            setOption("plotAreaBorderColor", "'#DADADA'");
            setOption("plotAreaBorderAlpha", "0.5");
            setOption("numberFormatter", "{precision:2, decimalSeparator:'" + CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator + "',thousandsSeparator:'" + CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator + "'}");
            cellFormating = "{0}";
        }

        public static void createFormulaData(Series serie)
        {
            serie.Clear();
            double start = getFormulaStart(serie);
            double increment = getFormulaIncrement(serie);
            string formula = serie.Option["Formula"].Replace("$", "{0}");

            if (serie.Option.ContainsKey("categories"))
            {
                string[] cats = serie.Option["categories"].Split(';');
                for (int i = 0; i < cats.Length; i++)
                {
                    serie.addData(cats[i], Helper.calculate(String.Format(formula, (start + i * increment).ToString(CultureInfo.InvariantCulture))).ToString());
                }
            }
            else if (serie.Option.ContainsKey("end"))
            {
                //Checks for End Value other than Default
                double end = 0;
                double.TryParse(serie.Option["end"], out end);
                if (serie.Option.ContainsKey("startDate"))
                {
                    DateTime startdate = serie.Option["startDate"].ToDate();
                    String Date = "";
                    int past = 0;
                    for (double i = 0; i < end; i += increment)
                    {
                        switch (serie.Chart.Option["dateIncrement"])
                        {
                            case "Sekunde":
                                Date = startdate.AddSeconds(past).ToShortDateString() + " " + startdate.AddSeconds(past).ToLongTimeString();
                                break;
                            case "Minute":
                                Date = startdate.AddMinutes(past).ToShortDateString() + " " + startdate.AddMinutes(past).ToShortTimeString();
                                break;
                            case "Stunde":
                                Date = startdate.AddHours(past).ToShortDateString() + " " + startdate.AddHours(past).ToShortTimeString();
                                break;
                            case "Tag":
                                Date = startdate.AddDays(past).ToShortDateString();
                                break;
                            case "Monat":
                                Date = startdate.AddMonths(past).ToString("MM.YYYY");
                                break;
                            case "Jahr":
                                Date = startdate.AddYears(past).ToString("YYYY");
                                break;
                        }
                        serie.addData(Date, Helper.calculate(String.Format(formula, (i).ToString(CultureInfo.InvariantCulture))).ToString(CultureInfo.InvariantCulture));
                        past++;
                    }
                }
                else
                {
                    for (double i = start; i <= end; i += increment)
                    {
                        serie.addData(i.ToString("0.00", CultureInfo.InvariantCulture), Helper.calculate(String.Format(formula, (i).ToString("0.00", CultureInfo.InvariantCulture))).ToString("0.0000", CultureInfo.InvariantCulture));
                    }
                }
            }
            else
            {
                for (int i = 0; i < 10; i++)
                {
                    serie.addData((start + i * increment).ToString(), Helper.calculate(String.Format(formula, (start + i * increment).ToString("0.00", CultureInfo.InvariantCulture))).ToString("0.0000", CultureInfo.InvariantCulture));
                }
            }
        }


        public String getData()
        {
            Dictionary<String, List<Data>> cat = new Dictionary<string, List<Data>>();
            foreach (Series y in Daten)
            {
                if (y.Option.ContainsKey("Formula") && y.Count == 0)
                {
                    createFormulaData(y);
                }
                foreach (Data x in y)
                {
                    if (!cat.ContainsKey(x.Name))
                    {
                        List<Data> dat = new List<Data>();
                        dat.Add(x);
                        cat.Add(x.Name, dat);
                    }
                    else
                    {
                        cat[x.Name].Add(x);
                    }
                }
            }

            string data = "[\n";


            int i = 0;
            foreach (KeyValuePair<string, List<Data>> y in cat)
            {
                data += "\n{" + "cat:'" + y.Key + "'";

                foreach (Data x in y.Value)
                {
                    foreach (KeyValuePair<string, string> kvp in x)
                    {
                        if (kvp.Key == "Value")
                        {

                            data += ",'" + x.Serie.FName + "_" + kvp.Key + "' : " + kvp.Value;

                        }
                        else
                        {
                            data += ",'" + x.Serie.Name + "_" + kvp.Key + "' : '" + kvp.Value + "'";
                        }
                    }
                }
                i++;
                data += "},";
            }

            data = data.Substring(0, data.Length - 1) + "\n]";

            return data;
        }

        private static double getFormulaIncrement(Series serie)
        {
            double increment = 1;
            if (serie.Option.ContainsKey("increment"))
            {
                double.TryParse(serie.Option["increment"], out increment);
            }
            return increment;
        }

        private static double getFormulaStart(Series serie)
        {
            double start = 0;
            if (serie.Option.ContainsKey("start"))
            {
                double.TryParse(serie.Option["start"], out start);
            }
            return start;
        }

        private static double getFormulaEnd(Series serie)
        {
            double end = 0;
            if (serie.Option.ContainsKey("end"))
            {
                double.TryParse(serie.Option["end"], out end);
            }
            return end;
        }


        public String getJS()
        {
            try
            {
                StringBuilder js = new StringBuilder(@"
AmCharts.ready(function () {
    // SERIAL CHART
    " + ClientID + "_chart = new AmCharts.AmSerialChart();\n" + ClientID + "_chart.dataProvider = " + ClientID + "_chartData;");
                foreach (KeyValuePair<string, string> option in _Options)
                {
                    if (!option.Key.Equals("dateIncrement"))
                        js.Append(String.Format("{0}_chart.{1} = {2};\n", ClientID, option.Key, option.Value));
                }
                if (Legend.Count > 0)
                    js.Append(Legend.getJS());
                if (ValueAxis.Count > 0)
                    js.Append(ValueAxis.getJS());
                if (CategoryAxis.Count > 0)
                    js.Append(CategoryAxis.getJS());
                if (ChartCursor.Count > 0)
                    js.Append(ChartCursor.getJS());
                js.Append(getSeriesJS());

                js.Append(ClientID + "_chart.write('" + ClientID + "_chartContainer');");
                return ClientID + "_chartData = " + getData() + ";" + js.ToString() + getDataTableJS() + "});";
            }
            catch (Exception ex)
            {
                errors = "<p class='error'>" + ex.ToString() + "</p>";
                return "";
            }
        }

        protected string getSeriesJS()
        {

            StringBuilder js = new StringBuilder();
            int i = 0;
            foreach (Series ser in Daten)
            {

                js.Append(String.Format("var {1}_graph{0} = new AmCharts.AmGraph();\n{1}_graph{0}.title = '{2}';\n{1}_graph{0}.valueField = '{0}_Value';\n", ser.FName, ClientID, ser.Name));
                foreach (KeyValuePair<string, string> option in ser.Option)
                {
                    if (option.Key != "Formula" && !option.Key.Equals("end") && !option.Key.Equals("increment") && !option.Key.Equals("start") && !option.Key.Equals("categories") && !option.Key.Equals("dateIncrement") && !option.Key.Equals("startDate"))
                    {
                        js.AppendLine(String.Format("{1}_graph{0}." + option.Key + " = " + option.Value + ";\n", ser.FName, ClientID));
                    }
                }
                js.AppendLine(String.Format("{1}_chart.addGraph({1}_graph{0});\n", ser.FName, ClientID));
                i++;
            }
            return js.ToString();

        }

        public override string getHTML()
        {
            html = "<div id='" + ClientID + "_chartContainer' style='height: " + Height + ";'></div>";
            if (useDateTable)
                using (StringWriter sw = new StringWriter())
                {
                    createDataTable().RenderControl(new HtmlTextWriter(sw));
                    html += "<div class='tableData'>" + sw.ToString() + "</div>";
                }
            return html;
        }

        private Table createDataTable()
        {

            Table table = new Table();
            table.ID = ClientID + "_dataTable";


            TableHeaderRow hrow = new TableHeaderRow();
            hrow.CssClass = "head";
            foreach (Series serie in this.Daten)
            {
                if (serie.Count == 0 && serie.Option.ContainsKey("Formula"))
                {
                    Coord.createFormulaData(serie);
                }
            }

            var x = from series in this.Daten
                    from data in series
                    group data.Name by data.Name;

            TableHeaderCell hCell = new TableHeaderCell() { Text = "Kategorie" };
            hrow.Cells.Add(hCell);
            Dictionary<string, double> ctotal = new Dictionary<string, double>();
            for (int i = 0; i < x.Count(); i++)
            {
                hCell = new TableHeaderCell() { Text = x.ElementAt(i).Key };
                ctotal.Add(x.ElementAt(i).Key, 0);
                hrow.Cells.Add(hCell);
            }
            hCell = new TableHeaderCell() { Text = "Gesamt" };
            hrow.Cells.Add(hCell);
            table.Rows.Add(hrow);
            int rid = 0;

            foreach (Series serie in this.Daten)
            {
                double rtotal = 0;
                TableRow row = new TableRow();
                row.CssClass = "values " + ((rid % 2 == 0) ? "even" : "odd");
                rid++;
                TableCell Cell = new TableCell() { Text = serie.Name };
                row.Cells.Add(Cell);

                for (int i = 0; i < x.Count(); i++)
                {
                    try
                    {
                        Cell = new TableCell() { Text = String.Format(cellFormating, double.Parse(serie.findData(x.ElementAt(i).Key)["Value"], CultureInfo.InvariantCulture)) };
                        ctotal[x.ElementAt(i).Key] += double.Parse(serie.findData(x.ElementAt(i).Key)["Value"], CultureInfo.InvariantCulture);
                        rtotal += double.Parse(serie.findData(x.ElementAt(i).Key)["Value"], CultureInfo.InvariantCulture);
                    }
                    catch (Exception ex)
                    {
                        Cell = new TableCell() { Text = String.Format(cellFormating, 0) };
                    }

                    Cell.ToolTip = serie.Name;

                    row.Cells.Add(Cell);
                }
                Cell = new TableCell() { CssClass = "summe", Text = String.Format(cellFormating, rtotal) };
                row.Cells.Add(Cell);
                table.Rows.Add(row);
            }
            TableRow grow = new TableRow();
            TableCell gCell = new TableCell() { Text = "Gesamt" };
            grow.Cells.Add(gCell);
            double gTotal = 0;
            foreach (KeyValuePair<string, double> d in ctotal)
            {
                gCell = new TableCell() { Text = String.Format(cellFormating, d.Value) };

                grow.Cells.Add(gCell);
                gTotal += d.Value;
            }
            grow.Cells.Add(new TableCell() { Text = String.Format(cellFormating, gTotal) });
            grow.CssClass = "summe";
            table.Rows.Add(grow);
            return table;

        }


        protected string getDataTableJS()
        {
            string js = "";
            if (false)
            {
                bool x = this.ValueAxis.ContainsKey("stackType");
                js = String.Format("createTable({0}_chart,'{0}', {1});", ClientID, x.ToString().ToLower());
            }
            return js;

        }


        public override Series addSeries(string Name)
        {
            Series tmp = base.addSeries(Name);

            tmp.setOption("type", "'column'");
            return tmp;
        }

        public Series addSeries(string Name, String Type)
        {
            Series tmp = base.addSeries(Name);

            setOption("type", "'" + Type + "'");
            return tmp;
        }


        public bool OldRendering = false;

        protected override void OnPreRender(EventArgs e)
        {

            JS = getJS();
            base.OnPreRender(e);
            if (OldRendering)
            {
                Page.Header.Controls.Add(new LiteralControl(String.Format("<script  src='{0}'  type='text/javascript' ></script>", Page.ClientScript.GetWebResourceUrl(this.GetType(), "HDI.Charts2.js.raphael.js"))));
                Page.Header.Controls.Add(new LiteralControl(String.Format("<script  src='{0}'  type='text/javascript' ></script>", Page.ClientScript.GetWebResourceUrl(this.GetType(), "HDI.Charts2.js.amcharts.2.5.0.js"))));
            }
            else
            {
                Page.Header.Controls.Add(new LiteralControl(String.Format("<script  src='{0}'  type='text/javascript' ></script>", Page.ClientScript.GetWebResourceUrl(this.GetType(), "HDI.Charts2.js.amcharts.2.6.13.js"))));
            } 
            Page.Header.Controls.Add(new LiteralControl(String.Format("<script  src='{0}'  type='text/javascript' ></script>", Page.ClientScript.GetWebResourceUrl(this.GetType(), "HDI.Charts2.js.createDatatable.js"))));

        }
    }
}
